﻿/*
 * copyright (c) 2009 hvbird
 *
 * This file is part of tdlib.
 *
 * tdlib is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * tdlib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

using System;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;

namespace TDLib.Security
{
    /// <summary>
    /// DES 加密
    /// 支持Key(钥匙)加密变化
    /// 支持还原
    /// 
    /// 演示操作：
    ///  // 64位，8个字节
    ///  string sSecretKey;
    ///
    ///  // 获取Key
    ///  sSecretKey = GenerateKey();
    ///
    ///  // 托管
    ///  GCHandle gch = GCHandle.Alloc( sSecretKey,GCHandleType.Pinned );
    ///
    ///  // 加密文件
    ///  EncryptFile(@"C:\MyData.txt",
    ///  @"C:\Encrypted.txt",
    ///  sSecretKey);
    ///
    ///  // 解密文件
    ///  DecryptFile(@"C:\Encrypted.txt",
    ///  @"C:\Decrypted.txt",
    ///  sSecretKey);
    ///
    ///  // 释放托管内容
    ///  ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2);
    ///  gch.Free();
    /// </summary>
    public class DES
    {
        /// <summary>
        /// 创建Key
        /// </summary>
        /// <returns></returns>
        public static string GenerateKey()
        {
            // 创建一个DES 算法的实例。自动产生Key
            DESCryptoServiceProvider desCrypto = (DESCryptoServiceProvider)DESCryptoServiceProvider.Create();

            // 返回自动创建的Key 用于加密
            string key = ASCIIEncoding.ASCII.GetString(desCrypto.Key);
            desCrypto.Clear();
            return key;
        }

        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="inputString">输入字符</param>
        /// <param name="key">Key</param>
        /// <returns>加密结果</returns>
        public static string EncryptString(string inputString, string key)
        {
            byte[] data = System.Text.Encoding.Default.GetBytes(inputString);
            byte[] result;
            DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
            DES.Key = ASCIIEncoding.ASCII.GetBytes(key);
            DES.IV = ASCIIEncoding.ASCII.GetBytes(key);
            using (ICryptoTransform desencrypt = DES.CreateEncryptor())
            {
                result = desencrypt.TransformFinalBlock(data, 0, data.Length);
                string desString = "";
                for (int i = 0; i < result.Length; i++)
                {
                    desString += result[i].ToString() + "-";
                }
                //return desString.TrimEnd('-');
                string value = BitConverter.ToString(result);
                DES.Clear();
                return value;
            }
        }

        /// <summary>
        /// 解密字符串
        /// </summary>
        /// <param name="inputString">输入字符</param>
        /// <param name="key">Key</param>
        /// <returns>解密结果</returns>
        public static string DecryptString(string inputString, string key)
        {
            string[] sInput = inputString.Split("-".ToCharArray());
            byte[] data = new byte[sInput.Length];
            byte[] result;
            for (int i = 0; i < sInput.Length; i++)
            {
                data[i] = byte.Parse(sInput[i], System.Globalization.NumberStyles.HexNumber);
            }

            DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
            DES.Key = ASCIIEncoding.ASCII.GetBytes(key);
            DES.IV = ASCIIEncoding.ASCII.GetBytes(key);
            using (ICryptoTransform desencrypt = DES.CreateDecryptor())
            {
                result = desencrypt.TransformFinalBlock(data, 0, data.Length);
                string value = System.Text.Encoding.Default.GetString(result);
                DES.Clear();
                return value;
            }
        }

        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="notEncryptStr">待加密的明文字符串</param>
        /// <returns>加密后的字符串</returns>
        public static string EncryptString(string notEncryptStr)
        {
            //初始化加密器生成器
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            byte[] byteNotEncrypt = Encoding.UTF8.GetBytes(notEncryptStr);
            using (MemoryStream encryptMs = new MemoryStream())
            {
                using (CryptoStream encryptCs = new CryptoStream(encryptMs, des.CreateEncryptor(des.Key, des.IV), CryptoStreamMode.Write))
                {
                    //加密数据
                    encryptCs.Write(byteNotEncrypt, 0, byteNotEncrypt.Length);
                    encryptCs.FlushFinalBlock();
                    encryptMs.Seek(0, SeekOrigin.Begin);

                    //将加密后的数据读取出来
                    byte[] byteEncrypt = new byte[1024];
                    int i = encryptMs.Read(byteEncrypt, 0, 1024);
                    //将加密后的字节转换为BASE64编码
                    string decryptStr = Convert.ToBase64String(byteEncrypt, 0, i);
                    des.Clear();
                    return decryptStr;
                }
            }
        }

        /// <summary>
        /// 解密字符串
        /// </summary>
        /// <param name="decryptStr">待解密的密文字符串</param>
        /// <returns>解密后的字符串</returns>
        public static string DecryptString(string decryptStr)
        {
            //初始化解密器生成器
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            byte[] byteNotDecrypt = Convert.FromBase64String(decryptStr);
            using (MemoryStream decryptMs = new MemoryStream(byteNotDecrypt))
            {
                using (CryptoStream decryptCs = new CryptoStream(decryptMs, des.CreateDecryptor(des.Key, des.IV), CryptoStreamMode.Read))
                {
                    //解密数据
                    byte[] byteDecrypt = new byte[1024];
                    int i = decryptCs.Read(byteDecrypt, 0, 1024);
                    //将解密后的字节转换为BASE64编码
                    string notEncryptStr = Encoding.UTF8.GetString(byteDecrypt, 0, i);
                    des.Clear();
                    return notEncryptStr;
                }
            }
        }

        /// <summary>
        /// 加密文件
        /// </summary>
        /// <param name="inputFilename">输入文件</param>
        /// <param name="outputFilename">输出文件</param>
        /// <param name="key">Key</param>
        public static void EncryptFile(string inputFilename, string outputFilename, string key)
        {
            using (FileStream fsInput = new FileStream(inputFilename, FileMode.Open, FileAccess.Read))
            {
                using (FileStream fsEncrypted = new FileStream(outputFilename, FileMode.Create, FileAccess.Write))
                {
                    DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
                    DES.Key = ASCIIEncoding.ASCII.GetBytes(key);
                    DES.IV = ASCIIEncoding.ASCII.GetBytes(key);
                    using (ICryptoTransform desencrypt = DES.CreateEncryptor())
                    {
                        using (CryptoStream cryptostream = new CryptoStream(fsEncrypted, desencrypt, CryptoStreamMode.Write))
                        {
                            byte[] bytearrayinput = new byte[fsInput.Length];
                            fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
                            cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
                            DES.Clear();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 解密文件
        /// </summary>
        /// <param name="inputFilename">输入文件</param>
        /// <param name="outputFilename">输出文件</param>
        /// <param name="key">Key</param>
        public static void DecryptFile(string inputFilename, string outputFilename, string key)
        {
            DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
            DES.Key = ASCIIEncoding.ASCII.GetBytes(key);
            DES.IV = ASCIIEncoding.ASCII.GetBytes(key);

            using (FileStream fsread = new FileStream(inputFilename, FileMode.Open, FileAccess.Read))
            {
                using (ICryptoTransform desdecrypt = DES.CreateDecryptor())
                {
                    using (CryptoStream cryptostreamDecr = new CryptoStream(fsread, desdecrypt, CryptoStreamMode.Read))
                    {
                        using (StreamWriter fsDecrypted = new StreamWriter(outputFilename))
                        {
                            fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
                            fsDecrypted.Flush();
                            DES.Clear();
                        }
                    }
                }
            }
        }

    }
}
